home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xmris / xmris.c < prev    next >
C/C++ Source or Header  |  1995-06-06  |  19KB  |  798 lines

  1. /*{{{  (C) 1992 Nathan Sidwell*/
  2. /*****************************************************************************
  3.             X M R I S V1.01
  4.             ---------------
  5.             (C) 1992 Nathan Sidwell
  6.  
  7. This program is copyright (C) 1992 Nathan Sidwell. This software and documentation
  8. is in the public domain. Permission is granted to distribute and compile
  9. verbatim copies of this software for non-commercial, non-profit use,
  10. without fee. The software may be modified, provided that both the above copyright
  11. notice and this permission notice appear.
  12.  
  13. No guarantee is given as to the robustness or suitability of this
  14. software for your computer.
  15.  
  16. Nathan Sidwell  INMOS UK |                 | nathan@inmos.co.uk       DoD#0390
  17. *****************************************************************************/
  18. /*}}}*/
  19. #include "xmris.h"
  20. #include <time.h>
  21. /*{{{  prototypes*/
  22. static void age_scores PROTOARGLIST((void));
  23. static void parse_args PROTOARGLIST((int, char **));
  24. /*}}}*/
  25. /*{{{  void add_score(increment, x, y)*/
  26. extern void add_score FUNCARGLIST((points, x, y))
  27. int       points  FUNCARGSEP
  28. int       x       FUNCARGSEP
  29. int       y       FUNCARGTERM
  30. /*
  31.  * adds the given score (which may be zero)
  32.  * and displays it at the top of the screen
  33.  * if the coordinate > 0 then add the score into the onboard list
  34.  */
  35. {
  36.   player.score += points;
  37.   /*{{{  text score*/
  38.   {
  39.     unsigned  length;
  40.     char      text[10];
  41.     int       ascent, descent;
  42.     int       direction;
  43.     XCharStruct chars;
  44.     int       x, y;
  45.     
  46.     length = itoa(text, player.score, 0);
  47.     XQueryTextExtents(display.display, font.font, text, length,
  48.     &direction, &ascent, &descent, &chars);
  49.     x = BORDER_LEFT + (CELL_WIDTH + GAP_WIDTH) * 4 -
  50.     CELL_WIDTH / 2 - chars.width;
  51.     y = (CELL_HEIGHT - ascent - descent) / 2 + ascent +
  52.     BORDER_TOP - CELL_HEIGHT;
  53.     XDrawImageString(display.display, display.back, GCN(GC_TEXT),
  54.     x, y, text, length);
  55.     add_background(x, y - ascent, chars.width, ascent + descent);
  56.   }
  57.   /*}}}*/
  58.   /*{{{  board score?*/
  59.   if(y)
  60.     {
  61.       unsigned  length;
  62.       char      text[10];
  63.       int       i;
  64.       SCORE     *sptr;
  65.       SPRITE    *dptr;
  66.     
  67.       dptr = &sprites[SPRITE_DIGITS];
  68.       length = itoa(text, points, 0);
  69.       /*{{{  remove oldest score?*/
  70.       if(update.score.scores == BOARD_SCORES)
  71.     {
  72.       add_background(update.score.list[0].place.x,
  73.           update.score.list[0].place.y,
  74.           DIGIT_WIDTH * 4, DIGIT_HEIGHT);
  75.       update.score.scores--;
  76.       memmove(&update.score.list[0], &update.score.list[1],
  77.           sizeof(SCORE) * update.score.scores);
  78.     }
  79.       /*}}}*/
  80.       sptr = &update.score.list[update.score.scores++];
  81.       sptr->count = SCORE_SHOW;
  82.       sptr->place.x = x - DIGIT_WIDTH * 2;
  83.       sptr->place.y = y - DIGIT_HEIGHT / 2;
  84.       /*{{{  centering*/
  85.       if(length != 4)
  86.     {
  87.       x = (4 - length) * (DIGIT_WIDTH / 2);
  88.       XCopyArea(display.display, dptr->image, sptr->image, GCN(GC_COPY),
  89.           10 * DIGIT_WIDTH, 0, x, DIGIT_HEIGHT, 0, 0);
  90.       XCopyArea(display.display, dptr->image, sptr->image, GCN(GC_COPY),
  91.           10 * DIGIT_WIDTH, 0, x, DIGIT_HEIGHT, 4 * DIGIT_WIDTH - x, 0);
  92.       XCopyArea(display.display, dptr->mask, sptr->mask, GCN(GC_COPY),
  93.           10 * DIGIT_WIDTH, 0, x, DIGIT_HEIGHT, 0, 0);
  94.       XCopyArea(display.display, dptr->mask, sptr->mask, GCN(GC_COPY),
  95.           10 * DIGIT_WIDTH, 0, x, DIGIT_HEIGHT, 4 * DIGIT_WIDTH - x, 0);
  96.     }
  97.       else
  98.     x = 0;
  99.       /*}}}*/
  100.       for(i = 0; i < length; i++, x += DIGIT_WIDTH)
  101.     {
  102.       XCopyArea(display.display, dptr->image, sptr->image, GCN(GC_COPY),
  103.           (text[i] - '0') * DIGIT_WIDTH, 0, DIGIT_WIDTH, DIGIT_HEIGHT,
  104.           x, 0);
  105.       XCopyArea(display.display, dptr->mask, sptr->mask, GCN(GC_COPY),
  106.           (text[i] - '0') * DIGIT_WIDTH, 0, DIGIT_WIDTH, DIGIT_HEIGHT,
  107.           x, 0);
  108.     }
  109.     }
  110.   /*}}}*/
  111.   return;
  112. }
  113. /*}}}*/
  114. /*{{{  void age_scores()*/
  115. static void age_scores FUNCARGVOID
  116. /*
  117.  * ages the onboard scores, and removes the old ones
  118.  */
  119. {
  120.   SCORE     *sptr;
  121.   int       i;
  122.  
  123.   for(sptr = update.score.list, i = update.score.scores; i--; sptr++)
  124.     if(!sptr->count--)
  125.       {
  126.     Pixmap    image, mask;
  127.     
  128.     add_background(sptr->place.x, sptr->place.y,
  129.         DIGIT_WIDTH * 4, DIGIT_HEIGHT);
  130.     mask = sptr->mask;
  131.     image = sptr->image;
  132.     memmove(sptr, sptr + 1, i * sizeof(SCORE));
  133.     sptr[i].mask = mask;
  134.     sptr[i].image = image;
  135.     update.score.scores--;
  136.     sptr--;
  137.      }
  138.   return;
  139. }
  140. /*}}}*/
  141. /*{{{  void calc_distances()*/
  142. extern void calc_distances FUNCARGVOID
  143. /*
  144.  * sets the distances from each cell to the player
  145.  * this is so the monsters have non-local knowlegde
  146.  * increment the non-zero cells
  147.  * this proceeds as a sort of flood fill operation, starting
  148.  * from the player's cell and moving outwards
  149.  */
  150. {
  151.   CELL    **aptr, **sptr;
  152.   CELL    *list[2][FLOOD_FILL];
  153.   CELL    *cptr;
  154.   int     toggle;
  155.   int     x, y;
  156.   int     count;
  157.  
  158.   global.broken = 0;
  159.   for(y = CELLS_DOWN; y--;)
  160.     {
  161.       cptr = BOARDCELL(0, y);
  162.       for(x = CELLS_ACROSS; x--; cptr++)
  163.     cptr->distance = cptr->visit ? 0 : 255;
  164.     }
  165.   toggle = 0;
  166.   cptr = BOARDCELL(monster.list[0].cell.x, monster.list[0].cell.y);
  167.   cptr->distance = count = 1;
  168.   list[0][0] = cptr;
  169.   list[0][1] = NULL;
  170.   while(list[toggle][0])
  171.   {
  172.     sptr = list[toggle];
  173.     toggle = !toggle;
  174.     aptr = list[toggle];
  175.     count++;
  176.     while(cptr = *sptr++)
  177.       {
  178.     CELL      *tptr;
  179.     
  180.     /*{{{  go up?*/
  181.     if(cptr->depths[0])
  182.       {
  183.         tptr = cptr - CELL_STRIDE;
  184.         if(tptr->visit && !tptr->distance)
  185.           {
  186.         tptr->distance = count;
  187.         *aptr++ = tptr;
  188.           }
  189.       }
  190.     /*}}}*/
  191.     /*{{{  go down?*/
  192.     if(cptr->depths[1])
  193.       {
  194.         tptr = cptr + CELL_STRIDE;
  195.         if(tptr->visit && !tptr->distance)
  196.           {
  197.         tptr->distance = count;
  198.         *aptr++ = tptr;
  199.           }
  200.       }
  201.     /*}}}*/
  202.     /*{{{  go left?*/
  203.     if(cptr->depths[2])
  204.       {
  205.         tptr = cptr - 1;
  206.         if(tptr->visit && !tptr->distance)
  207.           {
  208.         tptr->distance = count;
  209.         *aptr++ = tptr;
  210.           }
  211.       }
  212.     /*}}}*/
  213.     /*{{{  go right?*/
  214.     if(cptr->depths[3])
  215.       {
  216.         tptr = cptr + 1;
  217.         if(tptr->visit && !tptr->distance)
  218.           {
  219.         tptr->distance = count;
  220.         *aptr++ = tptr;
  221.           }
  222.       }
  223.     /*}}}*/
  224.     assert(aptr - list[toggle] < FLOOD_FILL);
  225.       }
  226.     *aptr = NULL;
  227.   }
  228.   return;
  229. }
  230. /*}}}*/
  231. /*{{{  void fatal_error(text, ...)*/
  232. extern void fatal_error FUNCARGLIST((text VARARG))
  233. char const *text FUNCARGSEP
  234. FUNCVARARG
  235. {
  236.   va_list   args;
  237.   
  238.   VARARGSET(args, text);
  239.   vfprintf(stderr, text, args);
  240.   fputc('\n', stderr);
  241.   release_resources();
  242.   exit(1);
  243. }
  244. /*}}}*/
  245. /*{{{  int itoa(text, n, width)*/
  246. extern int itoa FUNCARGLIST((text, number, digits))
  247. char    *text   FUNCARGSEP  /* output text (include 0) */
  248. int     number  FUNCARGSEP  /* number to convert */
  249. int     digits  FUNCARGTERM /* field width to convert into */
  250. /*
  251.  * formats an integer to a string
  252.  * in the specified number of digits
  253.  * pads leading zeros to ' '
  254.  * returns the number of characters used
  255.  */
  256. {
  257.   char    reverse[10];
  258.   int     l, length;
  259.  
  260.   l = 0;
  261.   do
  262.     {
  263.       reverse[l++] = number % 10 + '0';
  264.       number /= 10;
  265.     }
  266.   while(number);
  267.   if(!digits)
  268.     length = 0;
  269.   else if(l < digits)
  270.     {
  271.       length = digits - l;
  272.       memset(text, ' ', length);
  273.     }
  274.   else
  275.     {
  276.       length = 0;
  277.       l = digits;
  278.     }
  279.   while(l)
  280.     text[length++] = reverse[--l];
  281.   text[length] = 0;
  282.   return length;
  283. }
  284. /*}}}*/
  285. /*{{{  int main(argc, argv)*/
  286. extern int main FUNCARGLIST((argc, argv))
  287. int     argc    FUNCARGSEP
  288. char    **argv  FUNCARGTERM
  289. {
  290. #ifndef __STDC__
  291.   sprintf(title_text[1], "%s %s", XMRISVERSION, DATE);
  292. #endif
  293.   /*{{{  set defaults*/
  294.   {
  295.     argv[argc] = NULL;
  296.     display.name = NULL;
  297.     font.name = FONT_NAME;
  298.     flags.gender = GAME_GENDER;
  299.   }
  300.   /*}}}*/
  301.   parse_args(argc, argv);
  302.   /*{{{  help?*/
  303.   if(flags.help)
  304.     {
  305.       ARG const *aptr;
  306.       char const *ptr;
  307.     
  308.       if(!*argv)
  309.     ptr = game_name;
  310.       else
  311.     {
  312.       ptr = *argv;
  313.       for(ptr += strlen(ptr) - 1; ptr != *argv; ptr--)
  314.         if(ptr[-1] == '/')
  315.           break;
  316.     }
  317.       fprintf(stderr, "%s [option ...]\n", ptr);
  318.       fprintf(stderr, "%s %s\n", game_name, title_text[1]);
  319.       fprintf(stderr, "%s\n", title_text[0]);
  320.       for(aptr = args; aptr->arg; aptr++)
  321.     fprintf(stderr, "  %-8s %s\n", aptr->arg, aptr->help);
  322.       return 0;
  323.     }
  324.   /*}}}*/
  325.   create_resources(argc, argv);
  326.   timer_open();
  327.   XMapWindow(display.display, display.window);
  328.   XSelectInput(display.display, display.window, display.event_mask |
  329.       KeyPressMask | ButtonPressMask | KeyReleaseMask | PointerMotionMask);
  330.   while(!demo_mode())
  331.     /*{{{  game*/
  332.     {
  333.       extra.got = 0;
  334.       extra.select = 0;
  335.       extra.escape = 0;
  336.       extra.score = 0;
  337.       create_xtra_monster(0);
  338.       player.lives = START_LIVES;
  339.       player.score = 0;
  340.       player.screen = 0;
  341.       player.pressed = 0;
  342.       while(player.lives)
  343.     {
  344.       new_board();
  345.       zoom_board();
  346.       refresh_window();
  347.       history.prize <<= 1;
  348.       history.ending <<= 2;
  349.       timer_start(FRAME_RATE);
  350.       do
  351.         {
  352.           int     count;
  353.           
  354.           count = SCORE_SHOW;
  355.           /*{{{  initialize stuff*/
  356.           {
  357.         player.mouse.x = PLAYER_START_X;
  358.         player.mouse.y = PLAYER_START_Y;
  359.         player.mouse_dir = player.next_dir = 0;
  360.         global.state = 0;
  361.         monster.monsters = 0;
  362.         monster.delay = 0;
  363.         monster.den = monster.normals;
  364.         monster.drones = 0;
  365.         spawn_monster(4, 2, 2, PLAYER_START_X, PLAYER_START_Y, 0, 0);
  366.         monster.list[0].stop = 1;
  367.         player.pressed = 0;
  368.         player.ball.state = 8;
  369.         player.ball.count = 0;
  370.         player.old_ball.state = 0;
  371.           }
  372.           /*}}}*/
  373.           calc_distances();
  374.           draw_center(SPRITE_DEN);
  375.           show_updates();
  376.           player.ball.state = 0;
  377.           /*{{{  game loop*/
  378.           while(count)
  379.           {
  380.         age_scores();
  381.         if(process_xevents(1))
  382.           {
  383.             player.lives = 1;
  384.             monster.list[0].shot = 1;
  385.             global.state = 4;
  386.             count = 1;
  387.           }
  388.         if(global.state != 4)
  389.           move_player();
  390.         move_monsters();
  391.         bounce_ball();
  392.         move_apples();
  393.         if(!global.state)
  394.           /*{{{  monster escape?*/
  395.           {
  396.             if(!monster.delay && random() < DEN_ESCAPE_PROB)
  397.               monster.delay = DEN_ESCAPE_DELAY * DEN_ESCAPE_FLASH + 1;
  398.             if(monster.delay)
  399.               {
  400.             monster.delay--;
  401.             if(!(monster.delay % DEN_ESCAPE_FLASH))
  402.               draw_center(monster.delay / DEN_ESCAPE_FLASH &
  403.                   1 ? SPRITE_NORMAL + 4 : SPRITE_DEN);
  404.             if(!monster.delay)
  405.               {
  406.                 MONSTER   *mptr;
  407.                                                   
  408.                 mptr = spawn_monster(0, 2, 2, DEN_X, DEN_Y, 0, 0);
  409.                 monster.den--;
  410.                 if(!monster.den)
  411.                   {
  412.                 global.state++;
  413.                 draw_center(SPRITE_PRIZE_BASE +
  414.                   (player.screen - 1) % SPRITE_PRIZES);
  415.                   }
  416.               }
  417.               }
  418.           }
  419.           /*}}}*/
  420.         else if(global.state == 2 &&
  421.             !monster.den && !monster.drones)
  422.           global.state = 3;
  423.         fall_monsters();
  424.         /*{{{  ending?*/
  425.         if(global.state == 4)
  426.           {
  427.             if(update.score.scores || player.ball.state)
  428.               count++;
  429.             else
  430.               {
  431.             APPLE   *aptr;
  432.             int     i;
  433.                                             
  434.             for(aptr = apple.list, i = apple.apples; i--; aptr++)
  435.               if(aptr->state)
  436.                 {
  437.                   count++;
  438.                   break;
  439.                 }
  440.               }
  441.             count--;
  442.             if(player.ball.state == 1)
  443.               {
  444.             player.ball.state = 2;
  445.             player.ball.count = 0;
  446.               }
  447.             else if(player.ball.state == 3)
  448.               player.ball.state = 4;
  449.           }
  450.         /*}}}*/
  451.         /*{{{  extra stuff*/
  452.         if(!extra.escape)
  453.           {
  454.             unsigned  temp;
  455.                                             
  456.             if(random() < NEXT_XTRA_PROB)
  457.               new_xtra();
  458.             temp = player.score / 5000;
  459.             if(temp != extra.score)
  460.               {
  461.             extra.score = temp;
  462.             extra_escape();
  463.               }
  464.           }
  465.         else
  466.           extra.score = player.score / 5000;
  467.         /*}}}*/
  468.         if(!global.cherries || !monster.normals ||
  469.             monster.list[0].shot || extra.got == 0x1F)
  470.           global.state = 4;
  471.         if(global.broken)
  472.           calc_distances();
  473.         show_updates();
  474.         timer_wait();
  475.           }
  476.           /*}}}*/
  477.           if(extra.got == 0x1F)
  478.         /*{{{  extra life*/
  479.         {
  480.           extra_life();
  481.           extra.got = 0;
  482.           create_xtra_monster(extra.select);
  483.           monster.list[0].shot = 0;
  484.           history.ending |= 2;
  485.         }
  486.         /*}}}*/
  487.           else if(!monster.normals)
  488.         {
  489.           monster.list[0].shot = 0;
  490.           history.ending |= 1;
  491.         }
  492.           else if(!global.cherries)
  493.         monster.list[0].shot = 0;
  494.           else if(monster.list[0].shot)
  495.         /*{{{  die*/
  496.         {
  497.           unsigned  i;
  498.           unsigned  base, offset;
  499.           MONSTER   *mptr;
  500.                                         
  501.           player.ball.count = 8;
  502.           i = monster.list[0].face;
  503.           if(i >= 6)
  504.             i = 2 + (i & 1);
  505.           i = SPRITE_PLAYER + i * MONSTER_IMAGES;
  506.           for(base = 8; base--;)
  507.             if(player_dies[base] == i)
  508.               break;
  509.           offset = (base + 1) & 3;
  510.           base = base & 4;
  511.           for(i = 0; i != 8; i++)
  512.             {
  513.               unsigned  delay;
  514.                                         
  515.               if(process_xevents(0))
  516.             player.lives = 1;
  517.               monster.list[0].type =
  518.               player_dies[base + ((offset + i) & 3)];
  519.               show_updates();
  520.               for(delay = DIE_DELAY; delay--;)
  521.             timer_wait();
  522.             }
  523.           for(mptr = monster.list, i = monster.monsters; i--; mptr++)
  524.             add_background(mptr->pixel.x, mptr->pixel.y,
  525.             CELL_WIDTH, CELL_HEIGHT);
  526.           monster.monsters = 0;
  527.           player.lives--;
  528.           if(player.lives)
  529.             {
  530.               XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  531.               PIXELX(player.lives - 1, 0), PIXELY(CELLS_DOWN, 0),
  532.               CELL_WIDTH, CELL_HEIGHT);
  533.               add_background(PIXELX(player.lives - 1, 0),
  534.               PIXELY(CELLS_DOWN, 0), CELL_WIDTH, CELL_HEIGHT);
  535.             }
  536.           if(extra.escape)
  537.             {
  538.               extra.escape = 0;
  539.               draw_extra();
  540.             }
  541.           show_updates();
  542.         }
  543.         /*}}}*/
  544.           if(!monster.list[0].shot && !(player.screen % HISTORY_SHOW))
  545.         show_history();
  546.         }
  547.       while(monster.list[0].shot && player.lives);
  548.       timer_stop();
  549.     }
  550.     }
  551.     /*}}}*/
  552.   release_resources();
  553.   timer_close();
  554.   return 0;
  555. }
  556. /*}}}*/
  557. /*{{{  void parse_args(argc, argv)*/
  558. static void parse_args FUNCARGLIST((argc, argv))
  559. int     argc    FUNCARGSEP
  560. char    **argv  FUNCARGTERM
  561. {
  562.   char      **vptr;
  563.   static char const *names[2] = {"xmris", "xmsit"};
  564.  
  565.   vptr = argv;
  566.   /*{{{  determine gender of the game*/
  567.   if(*argv)
  568.     {
  569.       unsigned  length;
  570.       unsigned  other;
  571.       unsigned  index;
  572.     
  573.       length = strlen(*argv);
  574.       for(index = 2; index--;)
  575.     {
  576.       other = strlen(&names[index][1]);
  577.       if(length >= other &&
  578.           !strcmp(&(*argv)[length - other], &names[index][1]))
  579.         flags.gender = index;
  580.     }
  581.     }
  582.   /*}}}*/
  583.   /*{{{  parse all the arguments*/
  584.   while(*++vptr)
  585.     {
  586.       while(**vptr != '-')
  587.     vptr++;
  588.       if(*vptr)
  589.     {
  590.       ARG const *aptr;
  591.     
  592.       for(aptr = args; aptr->arg; aptr++)
  593.         if(!strcmp(aptr->arg, &(*vptr)[1]))
  594.           {
  595.         if(aptr->flag >= 0)
  596.           *(unsigned *)aptr->ptr = aptr->flag;
  597.         else
  598.           *(char **)aptr->ptr = *++vptr;
  599.         break;
  600.           }
  601.     }
  602.     }
  603.   /*}}}*/
  604.   game_name = names[flags.gender];
  605.   return;
  606. }
  607. /*}}}*/
  608. /*{{{  int process_xevents(pausable)*/
  609. extern int process_xevents FUNCARGLIST((pausable))
  610. int     pausable  FUNCARGTERM
  611. {
  612.   int       quit;
  613.   int       paused;
  614.  
  615.   player.motionevent = 0;
  616.   quit = 0;
  617.   paused = 0;
  618.   /*{{{  read the events*/
  619.   while(QLength(display.display) || paused)
  620.     {
  621.       XEvent    event;
  622.     
  623.       XNextEvent(display.display, &event);
  624.       if(event.xany.window != display.window)
  625.     continue;
  626.       switch (event.type)
  627.       {
  628.     /*{{{  case KeyPress:*/
  629.     case KeyPress:
  630.     /*
  631.      * When a key is pressed, we check to see if it is
  632.      * a control key. If so, then we set the relevant pressed bit.
  633.      */
  634.     {
  635.       char      chr;
  636.       KeySym    symbol;
  637.       XComposeStatus status;
  638.                       
  639.       XLookupString(&event.xkey, &chr, 1, &symbol, &status);
  640.       if(isupper(chr))
  641.         chr = tolower(chr);
  642.       if(chr == 'p' && pausable)
  643.         paused++;
  644.       else if(paused && chr == ' ')
  645.         player.motionevent = paused = 0;
  646.       else if((paused || !pausable) && chr == 'q')
  647.         {
  648.           paused = 0;
  649.           quit = 1;
  650.         }
  651.       else if(global.state > 5)
  652.         player.keyboard = player.button = 1;
  653.       else if(!paused && player.keyboard)
  654.         {
  655.           int       index;
  656.                     
  657.           for(index = 5; index--;)
  658.         if(chr == keystrokes[index])
  659.           {
  660.             if(index == 4)
  661.               player.button = 1;
  662.             else
  663.               player.pressed |= 1 << index;
  664.             break;
  665.           }
  666.         }
  667.       break;
  668.     }
  669.     /*}}}*/
  670.     /*{{{  case KeyRelease:*/
  671.     case KeyRelease:
  672.     /*
  673.      * when a key is released, we check to see if it is
  674.      * the controlling direction key. If so, then we stop
  675.      */
  676.     {
  677.       if(player.keyboard)
  678.         {
  679.           char      chr;
  680.           KeySym    symbol;
  681.           XComposeStatus status;
  682.           unsigned  index;
  683.                         
  684.           XLookupString(&event.xkey, &chr, 1, &symbol, &status);
  685.           if(isupper(chr))
  686.         chr = tolower(chr);
  687.           for(index = 5; index--;)
  688.         if(chr == keystrokes[index])
  689.           {
  690.             if(index == 4)
  691.               player.button = 0;
  692.             else
  693.               player.pressed &= ~(1 << index);
  694.             break;
  695.           }
  696.           break;
  697.         }
  698.     }
  699.     /*}}}*/
  700.     /*{{{  case MotionNotify:*/
  701.     case MotionNotify:
  702.     /*
  703.      * for mouse motion, we save the coordinate and process the
  704.      * final one only
  705.      */
  706.     {
  707.       player.raw_mouse.x = event.xmotion.x;
  708.       player.raw_mouse.y = event.xmotion.y;
  709.       player.motionevent = 1;
  710.       break;
  711.     }
  712.     /*}}}*/
  713.     /*{{{  case ButtonPress:*/
  714.     case ButtonPress:
  715.       if(!player.keyboard)
  716.         player.button = 1;
  717.       break;
  718.     /*}}}*/
  719.     /*{{{  case ButtonRelease:*/
  720.     case ButtonRelease:
  721.       if(!player.keyboard && player.throw)
  722.         player.button = 0;
  723.       break;
  724.     /*}}}*/
  725.     /*{{{  case Expose:*/
  726.     case Expose:
  727.       refresh_window();
  728.       break;
  729.     /*}}}*/
  730.     /*{{{  case UnmapNotify:*/
  731.     case UnmapNotify:
  732.       paused++;
  733.       break;
  734.     /*}}}*/
  735.     /*{{{  case MapNotify:*/
  736.     case MapNotify:
  737.       if(!pausable)
  738.         paused = 0;
  739.       break;
  740.     /*}}}*/
  741.     /*{{{  case PropertyNotify:*/
  742.     case PropertyNotify:
  743.       if(event.xproperty.atom == display.DEC_icon_atom)
  744.         paused++;
  745.       break;
  746.     /*}}}*/
  747.     default:
  748.       break;
  749.       }
  750.       /*{{{  started to pause?*/
  751.       if(paused == 1)
  752.     {
  753.       char const *text = "Space to continue, Q to quit";
  754.       TEXT      info;
  755.       unsigned  length;
  756.         
  757.       paused++;
  758.       length = strlen(text);
  759.       text_size(text, length, &info);
  760.       add_background(0, PIXELY(CELLS_DOWN, 0), WINDOW_WIDTH, CELL_HEIGHT);
  761.       XFillRectangle(display.display, display.copy, GCN(GC_CLEAR),
  762.           0, PIXELY(CELLS_DOWN, 0), WINDOW_WIDTH, CELL_HEIGHT);
  763.       XDrawImageString(display.display, display.copy, GCN(GC_TEXT),
  764.           WINDOW_WIDTH / 2 - info.width / 2,
  765.           PIXELY(CELLS_DOWN, CELL_HEIGHT / 2) +
  766.           (info.ascent - info.descent) / 2, text, length);
  767.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  768.           0, PIXELY(CELLS_DOWN, 0), WINDOW_WIDTH, CELL_HEIGHT,
  769.           0, PIXELY(CELLS_DOWN, 0));
  770.       XSync(display.display, False);
  771.     }
  772.       /*}}}*/
  773.     }
  774.   /*}}}*/
  775.   return quit;
  776. }
  777. /*}}}*/
  778. #if !defined(sco)
  779. /*{{{  unsigned random()*/
  780. extern unsigned random FUNCARGVOID
  781. /*
  782.  * a simple random number generator
  783.  * it generates 8 new bits of number at each call
  784.  * using a 31 bit maximal length linear feedback shift register
  785.  * the taps are bits 0 and 3
  786.  */
  787. {
  788.   unsigned  bits;
  789.  
  790.   if(!seed)
  791.     seed = time(NULL);
  792.   bits = ((seed >> 3) ^ seed) & 0xFF;
  793.   seed = (seed >> 8) | (bits << 23);
  794.   return bits;
  795. }
  796. /*}}}*/
  797. #endif
  798.